package com.hotelsystem.reservation.creators;

import java.io.InputStream;
import java.util.Scanner;

import com.hotelsystem.reservations.clientvalidation.ClientValidation;
import com.hotelsystem.reservations.persons.Client;
import com.hotelsystem.reservations.persons.ClientManagement;
import com.hotelsystem.reservations.persons.GenderEnum;

/**
 * Creates a client object, using command line interface.
 * 
 * <p>
 * Creating a object requires to specific "InputStream". The default CTOR uses
 * "System.in".
 * 
 * @author vanjiii
 * 
 */
public class ClientCreator {
	private ClientManagement clientManagement = new ClientManagement();
	private InputStream inputStream;
	private Scanner scanner = null;



	public ClientCreator(InputStream in) {
		this.inputStream = in;
	}

	public ClientCreator() {
		this(System.in);
	}

	/** Defines a class that can be used to define validations for attributes. */
	private abstract class ValidatorFunction {
		private String failureMessage;

		public abstract boolean doValidation(String value);

		public ValidatorFunction(String failureMessage) {
			this.failureMessage = failureMessage;
		}

		public String getFailureMessage() {
			return failureMessage;
		}
	}

	/**
	 * Create the Client Object, reading it from the stream specified in the
	 * constructor
	 * 
	 * @return The client
	 */
	public Client createNewClient() {
		scanner = new Scanner(inputStream);
		String firstName = getNextAttribute(
				"First Name", 
				new ValidatorFunction(
						"Name must start with uppercase, should be only characters and \" ' \" and \" - \" but not start or ends with these") {
					
					@Override
					public boolean doValidation(String value) {
						return new ClientValidation().isValidName(value, value);
					}
				});
		final String finalFirstName = firstName;
		String lastName =  getNextAttribute("Last Name", new ValidatorFunction(
				"Names should be unique") {
			@Override
			public boolean doValidation(String value) {
				return new ClientValidation().validateNameUniqueness(finalFirstName, value, clientManagement.getClients());
			}
		});
		String personalID = getNextAttribute("PersonalID", new ValidatorFunction(
				"ID must be 9 numbers") {
			
			@Override
			public boolean doValidation(String value) {
				return new ClientValidation().isValidId(value);
			}
		});
		String telephone = getNextAttribute(
				"Telephone",
				new ValidatorFunction(
						"Telephone Number should look like 0XXX-XX-XX-XX ")	{
					@Override
					public boolean doValidation(String value){
						return new ClientValidation().isTelephoneValid(value);
					}
				});
		String gender = getNextAttribute("Gender (M,F)", null);
		//By Dmitriy
		int age = Integer.parseInt(getNextAttribute("Age", 
				new ValidatorFunction(
							"Age must be between 0 and 120.") {
						@Override
						public boolean doValidation(String value) {
							return new ClientValidation().isValidAge(value);
						}
					}));
		String email = getNextAttribute(
				"Email",
				new ValidatorFunction(
						"Email should have single @ and one . after it. Should not end in . ") {
					@Override
					public boolean doValidation(String value) {
						return new ClientValidation().isValidEmail(value);
					}
				});
		String language = getNextAttribute("Language", null);
		String imageFilePath = getNextAttribute("Image file path", null);
		
		GenderEnum genderAsEnum;
		switch (gender.toUpperCase().charAt(0)) {
		case 'M':
			genderAsEnum = GenderEnum.MALE;
			break;
		case 'F':
			genderAsEnum = GenderEnum.FEMALE;
			break;
		default:
			genderAsEnum = GenderEnum.OTHER;
			break;
		}

		Client client = new Client(firstName, lastName, personalID,
				telephone, genderAsEnum, age, email, language, imageFilePath, null);
		
		return client;
	}

	private String getNextAttribute(String attribute, ValidatorFunction validator) {
		String result = null;
		while (true) {
			try {
				System.out.println("Please enter attrbute " + attribute);
				result = scanner.next();
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (validator == null || validator.doValidation(result)) {
				break;
			} else {
				System.out.println("Invalid value. Instructions: " + validator.getFailureMessage());
			}
		}

		return result;
	}

}
